package com.bytz.modules.cms.order.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.boya.cup.flowable.service.model.response.IdentityLink;
import com.bytz.common.exception.BytzBootException;
import com.bytz.modules.cms.domain.util.DecimalFormatUtil;
import com.bytz.modules.cms.order.constant.OrderConstants;
import com.bytz.modules.cms.order.entity.Order;
import com.bytz.modules.cms.order.service.IOrderEmailService;
import com.bytz.modules.cms.order.service.IOrderService;
import com.bytz.modules.cms.productLine.entity.ProductLine;
import com.bytz.modules.cms.productLine.service.IProductLineService;
import com.bytz.modules.cms.reseller.entity.Reseller;
import com.bytz.modules.cms.reseller.service.IResellerService;
import com.bytz.modules.cms.user.entity.CmsSysUser;
import com.bytz.modules.cms.user.service.ICmsSysUserService;
import com.bytz.modules.system.dto.EmailDto;
import com.bytz.modules.system.entity.SysDepart;
import com.bytz.modules.system.entity.SysUser;
import com.bytz.modules.system.entity.SysUserDepart;
import com.bytz.modules.system.service.INotifyService;
import com.bytz.modules.system.service.ISysDepartService;
import com.bytz.modules.system.service.ISysUserDepartService;
import com.google.common.collect.Sets;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderEmailServiceImpl implements IOrderEmailService {

    @Autowired
    private INotifyService notifyService;

    @Lazy
    @Autowired
    private IOrderService orderService;

    @Autowired
    private ICmsSysUserService sysUserService;

    @Autowired
    private IResellerService resellerService;

    @Autowired
    private ISysDepartService departService;

    @Autowired
    private ISysUserDepartService userDepartService;

    @Autowired
    private IProductLineService productLineService;

    @Value("${cms.domain}")
    private String cmsDomain;

    public String generateEmailContentByTemplate(Object dataModel, String templateName) throws IOException, TemplateException {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
        cfg.setClassForTemplateLoading(getClass(), "/mail");
        // 加载模板
        Template template = cfg.getTemplate(templateName + ".ftl");

        // 生成最终内容
        Writer out = new StringWriter();
        template.process(dataModel, out);
        return out.toString();
    }

    @Async
    @Override
    public void sendPrepayReminderEmail(Order order) {
        try {
            EmailDto emailDto = new EmailDto();
            // 获取销售信息
            CmsSysUser sysUser = sysUserService.getById(order.getSalesId());

            // 获取销售对应产品线的大客户部门

            List<CmsSysUser> kaDeptUsers = getKADeptUsers(sysUser.getCurrentDeptId());
            Set<String> emails = kaDeptUsers.stream().map(CmsSysUser::getEmail).filter(StringUtils::isNotBlank).collect(Collectors.toSet());

            // 获取销售邮箱
            emails.add(sysUser.getEmail());

            emailDto.setTos(emails.stream().filter(StrUtil::isNotBlank).collect(Collectors.toSet()));
            Reseller reseller = resellerService.getById(order.getResellerId());
            emailDto.setSubject("CMS[" + reseller.getResellerName() + "]订单预付通知");
            HashMap<Object, Object> dataModel = new HashMap<>();
            dataModel.put("order", order);
            dataModel.put("reseller", reseller);
            dataModel.put("orderDetailUrl", cmsDomain + OrderConstants.ReminderEmail.ORDER_DETAIL_PATH + order.getId());
            emailDto.setContent(generateEmailContentByTemplate(dataModel, "prepay"));

            emailDto.setHtml(true);
            notifyService.sendEmail(emailDto);
            orderService.setReminderFlagTrue(order.getId());
        } catch (Exception e) {
            log.error("发送预付邮件失败，orderId:" + order, e);
        }
    }

    private List<CmsSysUser> getKADeptUsers(String deptId) {
        return departService.lambdaQuery()
                .eq(SysDepart::getParentId, deptId)
                .eq(SysDepart::getDepartNameCn, OrderConstants.ReminderEmail.DEPART_DA_KE_HU)
                .list().stream()
                .findFirst()
                .map(SysDepart::getId)
                .map(id ->
                        sysUserService.getUserByRoleAndDept(null, null, null, id, null)
                ).orElse(Collections.emptyList());

    }

    /**
     * 查询到sap报价单（大客户处理完报价） 订单管理部门下的 订单录入发邮件；
     *
     * @param order 订单
     */
    @Async
    @Override
    public void sendSalesQuoteEmail(Order order) {
        try {
            EmailDto emailDto = new EmailDto();
            Set<String> emails = new HashSet<>();
            departService.lambdaQuery()
                    .eq(SysDepart::getDepartNameCn, OrderConstants.ReminderEmail.DING_DAN_LU_RU)
                    .list().stream().findFirst()
                    .ifPresent(sysDepart -> {
                        if (StringUtils.isNotBlank(sysDepart.getId())) {
                            // 根据部门id查找用户
                            Set<String> userIds = userDepartService.lambdaQuery().eq(SysUserDepart::getDepId, sysDepart.getId()).list().stream().map(SysUserDepart::getUserId).collect(Collectors.toSet());
                            Set<String> emailSet = sysUserService.getByIds(userIds).stream().map(SysUser::getEmail).collect(Collectors.toSet());
                            emails.addAll(emailSet);
                        }
                    });
            emailDto.setTos(emails.stream().filter(StrUtil::isNotBlank).collect(Collectors.toSet()));
            Reseller reseller = resellerService.getById(order.getResellerId());
            emailDto.setSubject("CMS[" + reseller.getResellerName() + "]SAP订单待处理");
            HashMap<Object, Object> dataModel = new HashMap<>();
            dataModel.put("order", order);
            dataModel.put("reseller", reseller);
            dataModel.put("orderDetailUrl", cmsDomain + OrderConstants.ReminderEmail.ORDER_DETAIL_PATH + order.getId());
            emailDto.setContent(generateEmailContentByTemplate(dataModel, "salesQuote"));

            emailDto.setHtml(true);
            notifyService.sendEmail(emailDto);
            orderService.setReminderFlagTrue(order.getId());
        } catch (Exception e) {
            log.error("发送SAP订单待处理邮件失败，orderId:" + order, e);
        }
    }

    /**
     * sap订单已创建之后给对应的销售发邮件
     * 20230919 给对应产品线大客户部门发订单
     *
     * @param order 订单
     */
    @Async
    @Override
    public void sendSapOrderEmail(Order order) {
        try {
            EmailDto emailDto = new EmailDto();
            String email = sysUserService.getById(order.getSalesId()).getEmail();
            //对应产品线
            String productLineCode = order.getProductLineCode();
            // 获取对应产品线的大客户部门
            Optional<ProductLine> productLine = productLineService.getByProductLineCode(productLineCode);
            List<CmsSysUser> kaDeptUsers = productLine.map(ProductLine::getDeptId)
                    .map(this::getKADeptUsers)
                    .orElse(Collections.emptyList());

            Set<String> emails = kaDeptUsers.stream().map(CmsSysUser::getEmail).filter(StringUtils::isNotBlank).collect(Collectors.toSet());

            // 获取销售邮箱
            emails.add(email);

            emailDto.setTos(emails.stream().filter(StringUtils::isNotBlank).collect(Collectors.toSet()));
            Reseller reseller = resellerService.getById(order.getResellerId());
            emailDto.setSubject("CMS[" + reseller.getResellerName() + "]SAP订单通知");
            HashMap<Object, Object> dataModel = new HashMap<>();
            dataModel.put("order", order);
            dataModel.put("reseller", reseller);
            dataModel.put("orderDetailUrl", cmsDomain + OrderConstants.ReminderEmail.ORDER_DETAIL_PATH + order.getId());
            emailDto.setContent(generateEmailContentByTemplate(dataModel, "sapOrder"));

            emailDto.setHtml(true);
            notifyService.sendEmail(emailDto);
            orderService.setReminderFlagTrue(order.getId());
        } catch (Exception e) {
            log.error("发送sap订单邮件失败，orderId:" + order, e);
        }
    }

    @Async
    @Override
    public void sendPrepayReminderEmail(String orderId) {
        sendPrepayReminderEmail(orderService.getById(orderId));
    }

    @Async
    @Override
    public void sendPickUpReminderEmail(Order order) {
        try {
            EmailDto emailDto = new EmailDto();
            CmsSysUser cmsSysUser = Optional.ofNullable(sysUserService.getById(order.getSalesId())).orElseThrow(() -> new BytzBootException("未找到该销售：" + order.getSalesId()));
            Set<String> emails = Sets.newHashSet(cmsSysUser.getEmail());
            emails.add(sysUserService.getOMEmailBySaleIds(order.getSalesId()));
            emailDto.setTos(emails.stream().filter(StrUtil::isNotBlank).collect(Collectors.toSet()));
            Reseller reseller = resellerService.getById(order.getResellerId());
            emailDto.setSubject("CMS[" + reseller.getResellerName() + "]订单提货通知");
            HashMap<Object, Object> dataModel = new HashMap<>();
            dataModel.put("order", order);
            dataModel.put("reseller", reseller);
            dataModel.put("pickUpListUrl", cmsDomain + OrderConstants.ReminderEmail.PICK_LIST + "?contractNumber=" + order.getContractNumber());
            dataModel.put("orderDetailUrl", cmsDomain + OrderConstants.ReminderEmail.ORDER_DETAIL_PATH + order.getId());
            emailDto.setContent(generateEmailContentByTemplate(dataModel, "pickup"));

            emailDto.setHtml(true);
            notifyService.sendEmail(emailDto);
        } catch (Exception e) {
            log.error("发送提货提醒邮件失败,order:" + order, e);
        }
    }

    @Async
    @Override
    public void sendFlowReminderEmail(Order order, List<IdentityLink> nextAuditUser, String processInstanceId) {
        try {
            if (CollectionUtil.isEmpty(nextAuditUser)) {
                return;
            }
            EmailDto emailDto = new EmailDto();
            Set<String> userIds = nextAuditUser.stream().map(IdentityLink::getAssignee).collect(Collectors.toSet());
            Set<String> emails = sysUserService.getByIds(userIds).stream()
                    .map(SysUser::getEmail)
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toSet());
            emailDto.setTos(emails);

            Reseller reseller = resellerService.getById(order.getResellerId());
            // [CMS待审批] 上海英旭（公司名前四位） - 89万元 （合同总价） - IEHF2306011DD （合同号码）
            String subject = "[CMS待审批] " +
                    StrUtil.sub(reseller.getResellerName(), 0, 4) + " - " +
                    DecimalFormatUtil.formatTenThousandMoney(order.getTotalPrice()) + " - " +
                    order.getContractNumber();
            emailDto.setSubject(subject);

            String auditUrl = cmsDomain + String.format(OrderConstants.ReminderEmail.ORDER_AUDIT, order.getId(), nextAuditUser.get(0).getTaskId(), processInstanceId);

            HashMap<Object, Object> dataModel = new HashMap<>();
            dataModel.put("order", order);
            dataModel.put("reseller", reseller);
            dataModel.put("auditUrl", auditUrl);

            emailDto.setContent(generateEmailContentByTemplate(dataModel, "flow"));
            emailDto.setHtml(true);
            notifyService.sendEmail(emailDto);
        } catch (Exception e) {
            log.error("发送审批提醒邮件失败,order:" + order, e);
        }
    }
}